(in-package :game)
;;;-----------------------------------------------------
(defmacro r-link (link-text &body link-code)
`(render-link
   #'(lambda (&rest args)
         (declare (ignorable args))
         ,@link-code)
   ,link-text))

(defmacro r-w-body (obj &body body)
`(defmethod render-widget-body (,obj &rest args &key (allow-other-keys t))
   (declare (ignorable args allow-other-keys))
      ,@body))

(defun i18 (str)
  ;; TODO internationalization
  str)
;;;-----------------------------------------------------
(defwidget notifiable-widget ()
())

(defgeneric notify (widget &rest args))

(defmethod notify-parent ((w notifiable-widget) &rest args)
  (when (and (widget-parent w) (equal 'main-window (class-name (class-of (widget-parent w)))))
    (apply #'notification-from-child (widget-parent w) w args)))
;;;-----------------------------------------------------
(defwidget login-widget (notifiable-widget)
((logged-in :initform nil)))

(defmethod my-login ((w login-widget) &rest args)
  ;;TODO args= arguments from login form
  (declare (ignorable args))
  (successful-login w))

(defmethod successful-login ((w login-widget))
  ;TODO
  (setf (slot-value w 'logged-in) t)
  (notify-parent w :login t))

(defmethod log-out ((w login-widget))
  (setf (slot-value w 'logged-in) nil)
  (notify-parent w :login nil))

(r-w-body (w login-widget)
  (if (slot-value w 'logged-in)
    (with-html 
      (:div :id "logoutDiv" 
        (r-link (i18 "Log out") (log-out w))))
    (with-html
      (:div :id "loginDiv"
        (with-html-form 
          (:post #'(lambda (&rest args) (apply #'my-login w args))
                 :id "loginForm"
                 :extra-submit-code "beforeLogin();"
                 :use-ajax-p t)
          (render-button "login" :value (i18 "login") :id "loginButton")
      )))))
;;;-------------------------------------------------------------------
(defwidget scoreboard (notifiable-widget)
())
(defmethod notify ((w scoreboard) &rest args)
  (declare (ignorable args)))

(r-w-body (w scoreboard)
  (with-html
    (:div :id "scoreboard" 
      (:div :class "winButtons" (:a :oclick "hideScore();" (i18 "hide"))))))

;;;-------------------------------------------------------------------
(defwidget gameboard (notifiable-widget)
 ((east :initform (make-instance 'card-holder :hand 'east))
  (player :initform (make-instance 'card-holder :hand 'player))
  (west :initform (make-instance 'card-holder :hand 'west))
  (prikup :initform (make-instance 'card-holder :hand 'prikup))))

(defmethod notify ((w gameboard) &rest args)
  (declare (ignorable args)))

(r-w-body (w gameboard)
  (with-html
    (:div :id "gameboard"
      (:div :id "toolbox" 
         (:a :onclick "showScore();" (i18 "show score")))
      (loop for h in '(east player west prikup) do
        (render-widget-body (slot-value w h))))))
;;;-------------------------------------------------------------------

(defwidget main-window (composite)
((login-w :initform (make-instance 'login-widget))))

(defmethod initialize-instance :after ((w main-window) &rest args &key (allow-other-keys t))
  (declare (ignorable args allow-other-keys))
  (setf (widget-children w) 
        (list (slot-value w 'login-w)
              (make-instance 'scoreboard)
              (make-instance 'gameboard))))

(defmethod notification-from-child ((w main-window) child &rest args)
  (loop for ch in (widget-children w) do
    (unless (equal ch child)
      (when (subtypep (class-of ch) 'notifiable-widget)
        (apply #'notify ch args)))))

(defmethod logged-in ((w main-window))
  (slot-value (slot-value w 'login-w) 'logged-in))

(defmethod (setf logged-in) (new-value (w main-window))
  (with-slots (login-w) w
    (with-slots (logged-in) login-w
      (when (not (equal logged-in new-value))
	(setf logged-in new-value)
	(mark-dirty w)))))

(defwidget card-holder ()
  ((game :initform (game-load))
   (hand-name :initform nil :initarg :hand))) 

(defmethod hand-id ((hand card-holder))
  (concatenate 'string "divHand" (symbol-name (slot-value hand 'hand-name))))
(defmethod cards-in-hand ((hand card-holder))
  (slot-value (slot-value hand 'game) (slot-value hand 'hand-name)))
(defmethod card-html (card (h card-holder))
  (with-html
    (:img :alt (format nil "~a ~a" (car card) (cdr card)) :src (format nil "/i/cards/~a~a.png" (cdr card) (car card)))))

(r-w-body (h card-holder)
(with-html
 (:div :class "card-holder" :id (hand-id h)
   (let ((cards (sort (cards-in-hand h) #'cards-compare-for-sort) ))
     (loop for prev-card = nil then card 
           for card in cards do
       (when (and prev-card (not (equal (cdr prev-card) (cdr card))))
         (card-html (cons 0 0) h))
         (card-html card h))))))

